#include "editorinterface.h"
#include "GUIDebug.h"
#include "globalstates.h"

EditorInterface::EditorInterface(EditorLogic *controller)
{
    this->controller = controller;
    setupMenus();
    setupCentralWidget();
    setupWindow();
    setupToolBar();
    setupModeBar();
    setupContextBar();
    setupPropertiesWidget();
    setupStatusBar();
    setupDefaults();
}

void EditorInterface::setupMenus() {
    setupFileMenu();
}

void EditorInterface::setupFileMenu() {
    loadAction = new QAction(tr("&Load"), this);
    saveAction = new QAction(tr("&Save"), this);
    quitAction = new QAction(tr("&Quit"), this);

    connect(loadAction, SIGNAL(triggered()), this, SLOT(load()));
    connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
    connect(quitAction, SIGNAL(triggered()), this, SLOT(quit()));

    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(loadAction);
    fileMenu->addAction(saveAction);
    fileMenu->addSeparator();
    fileMenu->addAction(quitAction);
}

void EditorInterface::setupCentralWidget() {
    glwindowWidget = GLWindow::getInstance();
    setCentralWidget(glwindowWidget);
    glwindowWidget->setFocusPolicy(Qt::StrongFocus);
}

void EditorInterface::setupWindow() {

    setWindowTitle(tr("Voxelab"));

}

void EditorInterface::setupToolBar() {
    tools = new VLToolBar();
    connect(tools, SIGNAL(brushClicked()), this, SLOT(brushToolSelected()));
    connect(tools, SIGNAL(fillClicked()), this, SLOT(fillToolSelected()));
    connect(tools, SIGNAL(selectClicked()), this, SLOT(selectToolSelected()));
    connect(tools, SIGNAL(eraserClicked()), this, SLOT(eraserToolSelected()));
    connect(tools, SIGNAL(transformClicked()), this, SLOT(transformToolSelected()));
    connect(tools, SIGNAL(colorClicked()), this, SLOT(colorToolSelected()));
    connect(tools, SIGNAL(magicWandClicked()), this, SLOT(magicWandToolSelected()));
    connect(tools, SIGNAL(gameElementsClicked()), this, SLOT(gameElementsToolSelected()));
    connect(tools, SIGNAL(terrainClicked()), this, SLOT(terrainToolSelected()));
    colorDialog = new QColorDialog(Qt::white);
    connect(colorDialog, SIGNAL(colorSelected(QColor)), tools, SLOT(changeColor(QColor)));
    connect(tools, SIGNAL(colorChanged(QColor)), this, SLOT(colorValueChanged(QColor)));

    addToolBar(Qt::LeftToolBarArea, tools);
}

void EditorInterface::setupModeBar() {

    modeBar = new VLModeBar(this);
    connect(modeBar, SIGNAL(modeChanged(QString)), this, SLOT(selectMode(QString)));
    connect(this, SIGNAL(createModeSelected()), this, SLOT(showToolBar()));
    connect(this, SIGNAL(gameModeSelected()), this, SLOT(hideToolBar()));

    addToolBar(Qt::TopToolBarArea, modeBar);
}

void EditorInterface::setupContextBar() {
    contextBar = new QToolBar(tr("Context Bar"), this);

    // default context
    brushCtx = new VLBrushContextWidget();
    connect(brushCtx, SIGNAL(shapeChanged(int)), this, SLOT(brushShapeChanged(int)));
    connect(brushCtx, SIGNAL(sizeChanged(int)), this, SLOT(brushSizeChanged(int)));
    connect(brushCtx, SIGNAL(heightChanged(int)), this, SLOT(brushHeightChanged(int)));
    connect(brushCtx, SIGNAL(breadthChanged(int)), this, SLOT(brushBreadthChanged(int)));
    connect(brushCtx, SIGNAL(shapeAdded(QString, int)), this, SLOT(addBrushShape(QString, int)));
    connect(brushCtx, SIGNAL(shapeDeleted(int)), this, SLOT(delBrushShape(int)));
    brushCtxAxn = addAndHideContext(brushCtx);

    eraserCtx = new VLEraserContextWidget();
    connect(eraserCtx, SIGNAL(shapeChanged(int)), this, SLOT(eraserShapeChanged(int)));
    connect(eraserCtx, SIGNAL(sizeChanged(int)), this, SLOT(eraserSizeChanged(int)));
    connect(eraserCtx, SIGNAL(heightChanged(int)), this, SLOT(eraserHeightChanged(int)));
    connect(eraserCtx, SIGNAL(breadthChanged(int)), this, SLOT(eraserBreadthChanged(int)));
    eraserCtxAxn = addAndHideContext(eraserCtx);

    selectorCtx = new VLSelectorContextWidget();
    selectorCtxAxn = addAndHideContext(selectorCtx);

    fillCtx = new VLFillContextWidget();
    fillCtxAxn = addAndHideContext(fillCtx);

    transformCtx = new VLTransformContextWidget();
    transformCtxAxn = addAndHideContext(transformCtx);

    magicWandCtx = new VLMagicWandContextWidget();
    magicWandCtxAxn = addAndHideContext(magicWandCtx);

    gameElementsCtx = VLGameElementsContextWidget::getInstance();
    connect(gameElementsCtx, SIGNAL(doorFaceSideChanged(int)), this, SLOT(setDoorFaceSide(int)));
    connect(gameElementsCtx, SIGNAL(enemySpeedChanged(int)), this, SLOT(setEnemySpeed(int)));
    connect(gameElementsCtx, SIGNAL(enemyWidthChanged(int)), this, SLOT(setEnemyWidth(int)));
    connect(gameElementsCtx, SIGNAL(enemyDepthChanged(int)), this, SLOT(setEnemyDepth(int)));
    connect(gameElementsCtx, SIGNAL(spikesDamageChanged(int)), this, SLOT(setSpikesDamage(int)));
    connect(gameElementsCtx, SIGNAL(ladderOrientationChanged(int)), this, SLOT(setLadderOrientation(int)));
    //connect(gameElementsCtx, SIGNAL(switchStateChanged(int)), this, SLOT(setSwitchState(int)));
    gameElementsCtxAxn = addAndHideContext(gameElementsCtx);

    terrainCtx = new VLTerrainContextWidget();
    connect(terrainCtx, SIGNAL(terrainEquationChanged(QString,QString,QString,QString,int,int,int,int,int,int)),
            this, SLOT(generateTerrain(QString,QString,QString,QString,int,int,int,int,int,int)));
    terrainCtxAxn = addAndHideContext(terrainCtx);

    addToolBar(Qt::TopToolBarArea, contextBar);
}

void EditorInterface::setupPropertiesWidget() {
    properties = new VLPropertiesWidget();
    propertiesDock = new QDockWidget(tr("Properties Editor"));
    propertiesDock->setWidget(properties);
    this->addDockWidget(Qt::RightDockWidgetArea, propertiesDock);
    propertiesDock->setVisible(false);
}

void EditorInterface::setupStatusBar() {
    status = this->statusBar();
    errorLabel = new QLabel("Ok");
    errorLabel->setIndent(3);
    errorLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    connect(glwindowWidget,SIGNAL(updateStatus(QString)),errorLabel,SLOT(setText(QString)));

    status->addWidget(errorLabel);
}

void EditorInterface::setupDefaults() {
    currentCtxAxn = brushCtxAxn;
    currentCtxAxn->setVisible(true);
}

RenderManager* EditorInterface::getRenderManager() {
    return glwindowWidget->getRenderManager();
}

void EditorInterface::load() {
    QString loadName = QFileDialog::getOpenFileName();
    controller->load(loadName);
}

void EditorInterface::save() {
    QString saveName = QFileDialog::getSaveFileName();
    controller->save(saveName);

}

void EditorInterface::quit() {
    QMessageBox msgBox;
    msgBox.setWindowTitle(tr("Voxelab"));
    msgBox.setText(tr("Do you really want to quit?"));
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    msgBox.setDefaultButton(QMessageBox::No);
    if (msgBox.exec() == QMessageBox::Yes) {
        qApp->quit();
    }
}

void EditorInterface::brushToolSelected() {
    glwindowWidget->setSelectedTool(TOOL_BRUSH);
    setCurrentVisibleContext(brushCtxAxn);
}

void EditorInterface::selectToolSelected() {
    glwindowWidget->setSelectedTool(TOOL_SELECT);
    setCurrentVisibleContext(selectorCtxAxn);
}

void EditorInterface::eraserToolSelected() {
    glwindowWidget->setSelectedTool(TOOL_ERASER);
    setCurrentVisibleContext(eraserCtxAxn);
}

void EditorInterface::fillToolSelected() {
    glwindowWidget->setSelectedTool(TOOL_FILL);
    setCurrentVisibleContext(fillCtxAxn);
}

void EditorInterface::transformToolSelected() {
    glwindowWidget->setSelectedTool(TOOL_TRANSFORM);
    setCurrentVisibleContext(transformCtxAxn);
}

void EditorInterface::magicWandToolSelected() {
    glwindowWidget->setSelectedTool(TOOL_MAGIC_BRUSH);
    setCurrentVisibleContext(magicWandCtxAxn);
}

void EditorInterface::gameElementsToolSelected() {
    glwindowWidget->setSelectedTool(TOOL_GAME_ELEMENT);
    setCurrentVisibleContext(gameElementsCtxAxn);
}

void EditorInterface::terrainToolSelected() {
    glwindowWidget->setSelectedTool(TOOL_TERRAIN);
    setCurrentVisibleContext(terrainCtxAxn);
}

void EditorInterface::colorToolSelected() {
    colorDialog->show();
}

void EditorInterface::selectMode(const QString &mode) {
    if (mode.compare(tr("Create")) == 0 && glwindowWidget->getCurrentView() == VIEW_GAME_MODE) {
        glwindowWidget->setCurrentView(VIEW_EDITOR_MODE);
        propertiesDock->setVisible(false);
        showCurrentVisibleContext(true);
        emit createModeSelected();
    } else if (mode.compare(tr("Game")) == 0 && glwindowWidget->getCurrentView() == VIEW_EDITOR_MODE) {
        glwindowWidget->setCurrentView(VIEW_GAME_MODE);
        propertiesDock->setVisible(true);
        showCurrentVisibleContext(false);
        emit gameModeSelected();
    }
    glwindowWidget->update();
}

void EditorInterface::enterEvent(QEvent *event) {
    glwindowWidget->enterEvent(event);
}

void EditorInterface::leaveEvent(QEvent *event) {
    glwindowWidget->leaveEvent(event);
}

void EditorInterface::mousePressEvent(QMouseEvent *event) {
    glwindowWidget->mousePressEvent(event);
}

void EditorInterface::mouseMoveEvent(QMouseEvent *event) {
    glwindowWidget->mouseMoveEvent(event);
}

void EditorInterface::keyPressEvent(QKeyEvent *event) {
    glwindowWidget->keyPressEvent(event);
}

void EditorInterface::keyReleaseEvent(QKeyEvent *event) {
    glwindowWidget->keyReleaseEvent(event);
}

void EditorInterface::mouseReleaseEvent(QMouseEvent *event) {
    glwindowWidget->mouseReleaseEvent(event);
}

void EditorInterface::brushShapeChanged(int shape) {
    Result r = TOOL_BRUSH->setShape(shape + 1);
    status->showMessage(resultToString(r));
}

void EditorInterface::brushSizeChanged(int size) {
    Result r = TOOL_BRUSH->setSize(size);
    status->showMessage(resultToString(r));
}

void EditorInterface::brushHeightChanged(int height) {
    Result r = TOOL_BRUSH->setHeight(height);
    status->showMessage(resultToString(r));
}

void EditorInterface::brushBreadthChanged(int breadth) {
    Result r = TOOL_BRUSH->setBreadth(breadth);
    status->showMessage(resultToString(r));
}

void EditorInterface::addBrushShape(QString name, int index) {
    Result r = TOOL_BRUSH->addShape();
    status->showMessage(resultToString(r));
    r = TOOL_BRUSH->setShapeName(index, name.toStdString());
    status->showMessage(resultToString(r));
}

void EditorInterface::delBrushShape(int index) {
    Result r = TOOL_BRUSH->deleteShape(index + 1);
    status->showMessage(resultToString(r));
}

void EditorInterface::eraserShapeChanged(int shape) {
    Result r = TOOL_ERASER->setShape(shape + 1);
    status->showMessage(resultToString(r));
}

void EditorInterface::eraserSizeChanged(int size) {
    Result r = TOOL_ERASER->setSize(size);
    status->showMessage(resultToString(r));
}

void EditorInterface::eraserHeightChanged(int height) {
    Result r = TOOL_ERASER->setHeight(height);
    status->showMessage(resultToString(r));
}

void EditorInterface::eraserBreadthChanged(int breadth) {
    Result r = TOOL_ERASER->setBreadth(breadth);
    status->showMessage(resultToString(r));
}

void EditorInterface::setDoorFaceSide(int index) {
    ElementDoor *door = TOOL_GAME_ELEMENT->getCurrentElement<ElementDoor, DOOR>();
    if (door != 0) {
        door->setFaceSide(index);
    }
}
void EditorInterface::setEnemySpeed(int val) {
    ElementEnemy *enemy = TOOL_GAME_ELEMENT->getCurrentElement<ElementEnemy, ENEMY>();
    if (enemy != 0) {
        enemy->setSpeed(val);
    }
}
void EditorInterface::setEnemyWidth(int val) {
    ElementEnemy *enemy = TOOL_GAME_ELEMENT->getCurrentElement<ElementEnemy, ENEMY>();
    if (enemy != 0) {
        enemy->setDetectionWidth(val);
    }
}
void EditorInterface::setEnemyDepth(int val) {
    ElementEnemy *enemy = TOOL_GAME_ELEMENT->getCurrentElement<ElementEnemy, ENEMY>();
    if (enemy != 0) {
        enemy->setDetectionDepth(val);
    }
}
void EditorInterface::setSpikesDamage(int val) {
    ElementSpikes *spikes = TOOL_GAME_ELEMENT->getCurrentElement<ElementSpikes, SPIKES>();
    if (spikes != 0) {
        spikes->setDamage(val);
    }
}
void EditorInterface::setLadderOrientation(int index) {
    ElementLadder *ladder = TOOL_GAME_ELEMENT->getCurrentElement<ElementLadder, LADDER>();
    if (ladder != 0)ladder->setOrientation((ORIENTATION)index);

}

void EditorInterface::generateTerrain(QString surfaceEq, QString redEq, QString greenEq, QString blueEq, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
    vector3<int> *start = new vector3<int>(minX, minY, minZ);
    vector3<int> *end = new vector3<int>(maxX, maxY, maxZ);

    string s_surfaceEq = surfaceEq.toStdString();
    string s_redEq = redEq.toStdString();
    string s_blueEq = blueEq.toStdString();
    string s_greenEq = greenEq.toStdString();


    char *c_surfaceEq = new char[s_surfaceEq.size() + 1];
    strcpy(c_surfaceEq, s_surfaceEq.c_str());
    char *c_redEq = new char[s_redEq.size() + 1];
    strcpy(c_redEq, s_redEq.c_str());
    char *c_blueEq = new char[s_blueEq.size() + 1];
    strcpy(c_blueEq, s_blueEq.c_str());
    char *c_greenEq = new char[s_greenEq.size() + 1];
    strcpy(c_greenEq, s_greenEq.c_str());
    TOOL_TERRAIN->genTerrain(c_surfaceEq, c_redEq, c_blueEq, c_greenEq, *start, *end);
}

void EditorInterface::colorValueChanged(QColor color) {
    char red = color.red();
    char green = color.green();
    char blue = color.blue();
    GlobalStates::getInstance()->setRGB(red, green, blue);
}

void EditorInterface::hideToolBar() {
    tools->setVisible(false);
}

void EditorInterface::showToolBar() {
    tools->setVisible(true);
}

void EditorInterface::setCurrentVisibleContext(QAction *ctxAxn) {
    currentCtxAxn->setVisible(false);
    currentCtxAxn = ctxAxn;
    currentCtxAxn->setVisible(true);
}

void EditorInterface::showCurrentVisibleContext(bool visible) {
    currentCtxAxn->setVisible(visible);
}

QAction * EditorInterface::addAndHideContext(VLContextWidget *ctx) {
    QAction *axn = contextBar->addWidget(ctx);
    axn->setVisible(false);
    return axn;
}

QString EditorInterface::resultToString(Result r) {
    return QString(r.getMessage().c_str());
}
